package net.fabricmc.funeralobjects.mixin;

import cn.funeralobjects.minecraft.Application;
import cn.funeralobjects.minecraft.config.McAppConfiguration;
import com.mojang.authlib.GameProfileRepository;
import com.mojang.authlib.minecraft.MinecraftSessionService;
import com.mojang.datafixers.DataFixer;
import net.minecraft.resource.ResourcePackManager;
import net.minecraft.resource.ServerResourceManager;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.WorldGenerationProgressListenerFactory;
import net.minecraft.server.dedicated.MinecraftDedicatedServer;
import net.minecraft.util.UserCache;
import net.minecraft.util.registry.DynamicRegistryManager;
import net.minecraft.world.SaveProperties;
import net.minecraft.world.level.storage.LevelStorage;
import org.jetbrains.annotations.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;

import java.net.Proxy;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * @author FuneralObjects
 * Create date: 2020/11/10 5:31 AM
 */
@Mixin(MinecraftDedicatedServer.class)
public abstract class AbstractMinecraftMixinServer extends MinecraftServer {

    private ThreadPoolExecutor poolExecutor;
    private Logger logger;

    public AbstractMinecraftMixinServer(Thread serverThread, DynamicRegistryManager.Impl registryManager, LevelStorage.Session session, SaveProperties saveProperties, ResourcePackManager dataPackManager, Proxy proxy, DataFixer dataFixer, ServerResourceManager serverResourceManager, @Nullable MinecraftSessionService sessionService, @Nullable GameProfileRepository gameProfileRepo, @Nullable UserCache userCache, WorldGenerationProgressListenerFactory worldGenerationProgressListenerFactory) {
        super(serverThread, registryManager, session, saveProperties, dataPackManager, proxy, dataFixer, serverResourceManager, sessionService, gameProfileRepo, userCache, worldGenerationProgressListenerFactory);
    }


    @Inject(method = "setupServer", at = @At("TAIL"))
    private void setupServer(CallbackInfoReturnable<Boolean> info) {
        logger = LoggerFactory.getLogger("MixinAppServer");

        McAppConfiguration.minecraftServer = this;
        poolExecutor = new ThreadPoolExecutor(1, 1, 1, TimeUnit.MILLISECONDS, new LinkedBlockingDeque<>(1), r -> {
            Thread springApp = new Thread(r);
            springApp.setName("springApp");
            return springApp;
        });


        this.startApp();

    }

    @Inject(method = "shutdown", at = @At("HEAD"))
    private void stopServer(CallbackInfo ci) {
        this.stopApp();
    }

    protected synchronized void startApp() {
        logger.info("-- start application --");
        if (poolExecutor.isShutdown() || poolExecutor.getActiveCount() < 1) {
            poolExecutor.execute(() -> Application.main(new String[0]));
        }
    }

    protected synchronized void stopApp() {
        logger.info("-- stop application --");
        Application.stop();
        if (poolExecutor.getActiveCount() > 0) {
            poolExecutor.shutdownNow();
        }
    }


}
